#region File Description
//-----------------------------------------------------------------------------
// GameplayScreen.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using System.Collections.Generic;
using System.Threading;

//RELEVANT USING FOR THE ACCELEROMETER 33245
using Microsoft.Devices.Sensors;
// ADD Microsoft.Devices.Sensors INTO REFERENCES -->>>

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media; // for playing music
using System.IO.IsolatedStorage; // for storage

using GameStateManagement;


#endregion

namespace GameStateManagementSample
{
    /// <summary>
    /// This screen implements the actual game logic. It is just a
    /// placeholder to get the idea across: you'll probably want to
    /// put some more interesting gameplay in here!
    /// </summary>
    class GameplayScreen : GameScreen
    {
        #region Fields

        ContentManager content;
        SpriteFont gameFont;

        //REQUIRED STUFF FOR ACCELERATOR 33245
        SensorReadingEventArgs<AccelerometerReading> accelState;
        Accelerometer accelSensor;
        //END

        Viewport viewport;

        Enemy[] enemySprites;
        Explosion[] explosionSprites;

        int maxEnemies = 20;

        Random random = new Random();

        float pauseAlpha;

        InputAction pauseAction;

        

        //for check if enemy is already spawned for that second
        bool spawned;

        
        bool bulletActive;

        int backgroundY;
        int lives;
        int timeBetweenSpawns = 2;
        int bulletSpeed = 8;

        string debug;

        float bulletReloadTimeLeft = 0;
        float timeSinceAcceptableTouch = 0;

        //player and bullet are only single instances, not made into class
        Vector2 playerPosition;
        Vector2 bulletPosition;
        Vector2 bulletVelocity;
        BoundingBox playerBoundingBox;
        BoundingBox bulletBoundingBox;

        Texture2D playerBody;
        Texture2D playerHitbox;
        Texture2D enemyTexture;
        Texture2D explosionTexture;
        Texture2D backgroundTexture;
        Texture2D bullet;

        SoundEffect explosionSnd1;
        SoundEffect explosionSnd2;
        SoundEffect explosionSnd3;
        SoundEffect explosionSnd4;

        #endregion

        #region Initialization


        /// <summary>
        /// Constructor.
        /// </summary>
        public GameplayScreen()
        {
            TransitionOnTime = TimeSpan.FromSeconds(1.5);
            TransitionOffTime = TimeSpan.FromSeconds(0.5);

            pauseAction = new InputAction(
                new Buttons[] { Buttons.Start, Buttons.Back },
                new Keys[] { Keys.Escape },
                true);
        }


        /// <summary>
        /// Load content for the game.
        /// </summary>
        public override void Activate(bool instancePreserved)
        {
            ScreenManager.playMusic();
            viewport = ScreenManager.GraphicsDevice.Viewport;
            if (!instancePreserved)
            {
                EnabledGestures = GestureType.Flick;


                if (content == null)
                    content = new ContentManager(ScreenManager.Game.Services, "Content");

                //content loading
                gameFont = content.Load<SpriteFont>("gamefont");
                enemyTexture = content.Load<Texture2D>("enemy");
                playerBody = content.Load<Texture2D>("player_body");
                playerHitbox = content.Load<Texture2D>("player_hitbox");
                bullet = content.Load<Texture2D>("bullet");

                explosionTexture = content.Load<Texture2D>("explosion");
                backgroundTexture = content.Load<Texture2D>("sea");

                explosionSnd1 = content.Load<SoundEffect>("Explo1");
                explosionSnd2 = content.Load<SoundEffect>("Explo2");
                explosionSnd3 = content.Load<SoundEffect>("Explo3");
                explosionSnd4 = content.Load<SoundEffect>("Explo4");



                //vars
                debug = "debug";
                backgroundY = 0; // for background scrolling in draw
                lives = 3;   // as name implies
                spawned = false;
                bulletActive = false;

                //spawn player center of screen
                playerPosition = new Vector2((float)viewport.Bounds.Center.X, (float)viewport.Bounds.Center.Y);


                enemySprites = new Enemy[maxEnemies];
                explosionSprites = new Explosion[10];

                for (int i = 0; i < explosionSprites.Length; i++)
                {
                    explosionSprites[i] = new Explosion();
                    explosionSprites[i].setTexture(explosionTexture);
                }

                for (int i = 0; i < enemySprites.Length; i++)
                {
                    enemySprites[i] = new Enemy();
                }



                // A real game would probably have more content than this sample, so
                // it would take longer to load. We simulate that by delaying for a
                // while, giving you a chance to admire the beautiful loading screen.
                Thread.Sleep(1000);

                // once the load has finished, we use ResetElapsedTime to tell the game's
                // timing mechanism that we have just finished a very long frame, and that
                // it should not try to catch up.
                ScreenManager.Game.ResetElapsedTime();
            }

            //
            //INIT FOR THE ACCELERATOR 33245
            //
            accelSensor = new Accelerometer();

            if (accelSensor.State == SensorState.Ready)
            {
                accelSensor.CurrentValueChanged += (s, e) =>
                {
                    accelState = e;
                };

                accelSensor.Start();
            }
            //
            //END INIT FOR ACCELERATOR
            //

        }


        public override void Deactivate()
        {

            base.Deactivate();
        }


        /// <summary>
        /// Unload graphics content used by the game.
        /// </summary>
        public override void Unload()
        {
            content.Unload();
        }


        #endregion

        #region Update and Draw


        /// <summary>
        /// Updates the state of the game. This method checks the GameScreen.IsActive
        /// property, so the game will stop updating when the pause menu is active,
        /// or if you tab away to a different application.
        /// </summary>
        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
                                                       bool coveredByOtherScreen)
        {
            base.Update(gameTime, otherScreenHasFocus, false);

            // Gradually fade in or out depending on whether we are covered by the pause screen.
            if (coveredByOtherScreen)
                pauseAlpha = Math.Min(pauseAlpha + 1f / 32, 1);
            else
                pauseAlpha = Math.Max(pauseAlpha - 1f / 32, 0);

            if (lives <= 0)
            {
                ScreenManager.Vibrate(200);
                LoadingScreen.Load(ScreenManager, false, null, new BackgroundScreen(),
                                                       new LoseScreen(((int)ScreenManager.totalTime).ToString()));
            }

            

            //GAMEPLAY RELATED
            if (IsActive)
            {
                ScreenManager.totalTime += (float)gameTime.ElapsedGameTime.TotalSeconds;
                //spawning planes every x seconds
                if (gameTime.TotalGameTime.Seconds % timeBetweenSpawns == 0 && !spawned)
                {
                    for (int i = 0; i < maxEnemies; i++)
                    {
                        if (!enemySprites[i].active)
                        {
                            int randomDirection;
                            randomDirection = (int)(random.NextDouble() * 4);
                            enemySprites[i].Initialize(ref viewport, randomDirection, enemyTexture);
                            break;
                        }
                    }
                    spawned = true;
                }
                //limit for one spawn in the previous second, timer reset as a quick workaround
                if (spawned)
                {
                    if (gameTime.TotalGameTime.Seconds % timeBetweenSpawns == 1)
                        spawned = false;
                }

                //run enemy updates
                for (int i = 0; i < maxEnemies; i++)
                {
                    if (enemySprites[i].active)
                    {
                        enemySprites[i].Update();
                    }
                }

                //bullet update
                if (bulletActive)
                {
                    bulletPosition += bulletVelocity;

                    //leaves screen then deactivate
                    if (bulletPosition.X - bullet.Height < viewport.Bounds.Left ||
                        bulletPosition.X + bullet.Height > viewport.Bounds.Right ||
                        bulletPosition.Y - bullet.Height < viewport.Bounds.Top ||
                        bulletPosition.Y + bullet.Height > viewport.Bounds.Bottom)
                    {
                        bulletActive = false;
                    }
                }

                if (bulletReloadTimeLeft > 0)
                {
                    bulletReloadTimeLeft -= (float)gameTime.ElapsedGameTime.TotalSeconds;
                }
                else if (bulletReloadTimeLeft < 0)
                {
                    bulletReloadTimeLeft = 0;
                }

                //player prevent from leaving playing area
                if (playerPosition.X < viewport.Bounds.Left + 50)
                    playerPosition.X = viewport.Bounds.Left + 50;
                else
                    if (playerPosition.X > viewport.Bounds.Right - 50)
                        playerPosition.X = viewport.Bounds.Right - 50;

                if (playerPosition.Y < viewport.Bounds.Top + 50)
                    playerPosition.Y = viewport.Bounds.Top + 50;
                else
                    if (playerPosition.Y > viewport.Bounds.Bottom - 50)
                        playerPosition.Y = viewport.Bounds.Bottom - 50;
                ////////////////
                //COLLISION CHECKING
                playerBoundingBox.Min = new Vector3((playerPosition.X - (playerHitbox.Width / 2)), (playerPosition.Y - (playerHitbox.Height / 2)), 0);
                playerBoundingBox.Max = new Vector3((playerPosition.X + (playerHitbox.Width / 2)), (playerPosition.Y + (playerHitbox.Height / 2)), 0);

                bulletBoundingBox.Min = new Vector3((bulletPosition.X - (bullet.Width / 2)), (bulletPosition.Y - (bullet.Height / 2)), 0);
                bulletBoundingBox.Max = new Vector3((bulletPosition.X + (bullet.Width / 2)), (bulletPosition.Y + (bullet.Height / 2)), 0);

                for (int i = 0; i < maxEnemies; i++)
                {
                    if (enemySprites[i].active)
                    {
                        if (playerBoundingBox.Intersects(enemySprites[i].boundingBox))
                        {
                            enemySprites[i].active = false;
                            for (int x = 0; x < explosionSprites.Length; x++)
                            {
                                if (!explosionSprites[x].active)
                                {
                                    explosionSprites[x].Activate(enemySprites[i].getCenter(), gameTime);
                                    if (ScreenManager.soundEnabled)
                                    {
                                        ExplosionSound();
                                    }
                                    break;
                                }
                            }
                            ScreenManager.Vibrate(200);
                            lives--;
                        }
                        if (bulletActive && bulletBoundingBox.Intersects(enemySprites[i].boundingBox))
                        {
                            enemySprites[i].active = false;
                            bulletActive = false;
                            for (int x = 0; x < explosionSprites.Length; x++)
                            {
                                if (!explosionSprites[x].active)
                                {
                                    explosionSprites[x].Activate(enemySprites[i].getCenter(), gameTime);
                                    if (ScreenManager.soundEnabled)
                                    {
                                        ExplosionSound();
                                    }
                                    break;
                                }
                            }
                            ScreenManager.Vibrate(133);
                        }
                    }
                }
                //
                ////////////////

            }
        }


        /// <summary>
        /// Plays random explosion sound
        /// </summary>
        public void ExplosionSound()
        {
            switch (random.Next(3))
            {
                case 0:
                    explosionSnd1.Play();
                    break;
                case 1:
                    explosionSnd2.Play();
                    break;
                case 2:
                    explosionSnd3.Play();
                    break;
                case 3:
                    explosionSnd4.Play();
                    break;
            }
        }

        /// <summary>
        /// Starts the bullet from the ship's center (as required for the flick)
        /// </summary>
        /// <param name="bulletVel"></param>
        public void BulletActivate(Vector2 bulletVel)
        {
            bulletActive = true;
            bulletPosition = playerPosition;
            bulletVelocity = bulletVel;
        }

        /// <summary>
        /// Lets the game respond to player input. Unlike the Update method,
        /// this will only be called when the gameplay screen is active.
        /// </summary>
        public override void HandleInput(GameTime gameTime, InputState input)
        {


            if (input == null)
                throw new ArgumentNullException("input");

            // Look up inputs for the active player profile.
            int playerIndex = (int)ControllingPlayer.Value;


            // Gesture is only needed for bullet firing; if bullet can't be fired then no point running gestures
            if (bulletReloadTimeLeft == 0 && input.TouchState.Count > 0)
            {
                // convert the touch position into a mini 2x2 box for easy "collision" detection; a bit of cheating since
                // point is incompatible with vector2 despite storing the same values

                BoundingBox touchBox = new BoundingBox(
                    new Vector3((int)input.TouchState[0].Position.X - 1, (int)input.TouchState[0].Position.Y - 1, 0),
                    new Vector3((int)input.TouchState[0].Position.X + 1, (int)input.TouchState[0].Position.Y + 1, 0));
                if (playerBoundingBox.Intersects(touchBox))
                {
                    //this is to let the flick gesture work since it needs time to have a delta
                    timeSinceAcceptableTouch = 1;
                }
                if (timeSinceAcceptableTouch > 0)
                {
                    foreach (GestureSample playerinput in input.Gestures)
                    {
                        // nasty trigo stuff that took a while to figure out
                        if (playerinput.GestureType == GestureType.Flick)
                        {
                            bulletReloadTimeLeft = 3;
                            //honestly still have no idea what i was doing, just changed values around till it worked as intended
                            double angle = Math.Atan(playerinput.Delta.X / playerinput.Delta.Y);
                            if (playerinput.Delta.Y < 0)
                                angle -= Math.PI;
                            //debug = (angle*180/Math.PI).ToString(); //<-- painful trigo debugging
                            BulletActivate(new Vector2((float)Math.Sin(angle) * bulletSpeed, (float)Math.Cos(angle) * bulletSpeed));
                        }

                    }
                    timeSinceAcceptableTouch -= (float)gameTime.ElapsedGameTime.TotalSeconds; ;
                    if (timeSinceAcceptableTouch < 0)
                        timeSinceAcceptableTouch = 0;
                }

            }
            //
            //ACCELEROMETER
            //STUFF
            // 33245
            Vector3 accelerationInfo = accelState == null ? Vector3.Zero :
            new Vector3((float)accelState.SensorReading.Acceleration.X,
            (float)accelState.SensorReading.Acceleration.Y, (float)accelState.SensorReading.Acceleration.Z);

            //Player X position
            float movementX = 0.0f;

            if (Math.Abs(accelerationInfo.X) > 0.10f)
            {
                if (accelerationInfo.X > 0.0f)
                {
                    movementX = 2.0f;
                }
                else
                {
                    movementX = -2.0f;
                }
            }

            //CHANGE THIS IF GAME IS POTRAIT MODE
            playerPosition.Y -= movementX;

            //Player Y position
            float movementY = 0.0f;

            if (Math.Abs(accelerationInfo.Y) > 0.10f)
            {
                if (accelerationInfo.Y > 0.0f)
                {
                    movementY = -2.0f;
                }
                else
                {
                    movementY = 2.0f;
                }
            }

            //CHANGE THIS IF GAME IS POTRAIT MODE
            playerPosition.X += movementY;

            ////
            ////END OF ACCELEROMETER STUFF
            ////



            PlayerIndex player;
            if (pauseAction.Evaluate(input, ControllingPlayer, out player))
            {
#if WINDOWS_PHONE
                ScreenManager.AddScreen(new PhonePauseScreen(), ControllingPlayer);
#else
                ScreenManager.AddScreen(new PauseMenuScreen(), ControllingPlayer);
#endif
            }
        }


        /// <summary>
        /// Draws the gameplay screen.
        /// </summary>
        public override void Draw(GameTime gameTime)
        {
            //This black should never be seen!
            ScreenManager.GraphicsDevice.Clear(ClearOptions.Target, Color.Black, 0, 0);

            //animation for player
            int playerFPS = 6;
            int playerBodyFrameTotal = 2;
            int frame = (int)(gameTime.TotalGameTime.TotalSeconds * playerFPS) % playerBodyFrameTotal;

            //animation for background
            int backgroundMovementSpeed = 50;
            if (IsActive)
                backgroundY = (int)(gameTime.TotalGameTime.TotalSeconds * backgroundMovementSpeed) % backgroundTexture.Height;

            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;

            spriteBatch.Begin();

            //sea background drawing
            //uses two that move and reset such that there is constant scrolling
            spriteBatch.Draw(backgroundTexture, new Vector2(0, backgroundY), Color.White);
            spriteBatch.Draw(backgroundTexture, new Vector2(0, backgroundY - backgroundTexture.Height), Color.White);

            if (bulletReloadTimeLeft == 0)
                spriteBatch.DrawString(gameFont, "Cannon ready!", new Vector2(260, 0), Color.White);

            spriteBatch.DrawString(gameFont, "Lives: " + lives, new Vector2(0, 400), Color.White);

            spriteBatch.DrawString(gameFont, "Time: " + ((int)ScreenManager.totalTime).ToString(), new Vector2(0, 370), Color.White);

            //spriteBatch.DrawString(gameFont, debug, new Vector2(0, 300), Color.White);

            //body of ship
            spriteBatch.Draw(playerBody,
                new Vector2(playerPosition.X - playerBody.Width / playerBodyFrameTotal / 2,
                    playerPosition.Y - playerBody.Height / 2),
                new Rectangle(frame * playerBody.Width / playerBodyFrameTotal, 0,
                    playerBody.Width / playerBodyFrameTotal, playerBody.Height),
                Color.White);
            //center of ship, hitbox
            spriteBatch.Draw(playerHitbox,
                new Vector2(playerPosition.X - playerHitbox.Width / 2, playerPosition.Y - playerHitbox.Height / 2),
                Color.White);

            //bullet
            if (bulletActive)
            {
                spriteBatch.Draw(bullet, bulletPosition, Color.White);
            }

            //enemy draw
            for (int x = 0; x < maxEnemies; x++)
            {
                enemySprites[x].Draw(gameTime, spriteBatch);
            }

            //explosions draw
            for (int i = 0; i < explosionSprites.Length; i++)
            {
                explosionSprites[i].Draw(gameTime, spriteBatch);
            }


            spriteBatch.End();

            // If the game is transitioning on or off, fade it out to black.
            if (TransitionPosition > 0 || pauseAlpha > 0)
            {
                float alpha = MathHelper.Lerp(1f - TransitionAlpha, 1f, pauseAlpha / 2);

                ScreenManager.FadeBackBufferToBlack(alpha);
            }
        }

        #endregion

    }
}

